/**
 *  name属性
 *  只是协助调试，不能使用name属性来回去对函数的引用
 */
//函数声明
function doSomething() {
  //code
}
//函数表达式
var doAnotherThing = function() {
  //code
}
console.log(doSomething.name)
console.log(doAnotherThing.name)
//---------------------------------------------------------------
/**
 *  name属性特殊情况
 */
var doSomething = function doSomethingElse() {
  //code
}
var person = {
  get firstName() {//getter函数
    return 'funlee'
  },
  sayName:function() {
    console.log(this.name)
  }
}
console.log(doSomething.name);//doSomethingElse
console.log(person.sayName.name);//sayName
console.log(person.firstName.name);//get firstName

/**
 *  bind 和 Function构造函数情况下的name
 */

function doSome() {
  //code
}
console.log(doSome.bind().name)//bound doSome
console.log((new Function()).name)//anonymous
//---------------------------------------------------------------
function Person(name) {
  if(this instanceof Person) {
    this.name = name;
  } else {
    throw new Error('必须通过new关键字来调用Person。')
  }
}
var p1 = new Person('funlee');
var p2 = Person.call(person,'hello') //居然有效！！！！！！
/**
 *  利用元属性检测是否通过new关键字调用函数
 *  解决上述ES5 的 bug
 */
function Person(name) {
  if(typeof new.target !== 'undefined') {
    this.name = name;
  } else {
    throw new Error('必须通过new关键字来调用Person。')
  }
}
var p1 = new Person('funlee');
var p2 = Person.call(person,'hello') //错误
//---------------------------------------------------------------
/**
 *  块级函数
 */
if(true) {
  function doSome() {//块级函数会被提升至块的顶部
    console.log(123)
  }
  let doAnother = function() { //函数表达式：执行过程流出了代码块，函数就会被移除
    console.log(456)
  }
  doAnother()
}
doSome()
doAnother()///报错
//---------------------------------------------------------------
/**
 *  箭头函数
 */
//当只有一个参数时，可以直接写参数名，箭头紧随其后，箭头右侧的表达式被求值后便立即返回
 let result = value => value * 20;
 result(90)
 //没有参数，要写一组没有内容的小括号
 let me = () => 'funlee'
 me()

//创建IIFE
let person = function(name) {
  return {
    getName:function() {
      return name;
    }
  }
}('funlee')
console.log(person.getName())//funlee

//箭头函数版
let person = ((name) => {
  return {
    getName:function() {
      return name
    }
  }
})('funlee')
console.log(person.getName())//funlee
//---------------------------------------------------------------
/**
 *  没有this绑定
 */
let pageHandler = {
  init:function() {
    document.addEventListener('click',(function(event) {
      this.doSomthing(event.type)
    }).bind(this).false)
  },
  doSomthing:function(type) {
    //code
  }
}
//使用箭头函数解决上述问题
let pageHandler = {
  init:function() {
    document.addEventListener('click',
      event => this.doSomthing(event.type),false)//函数体内唯一的一条执行语句，可以不必使用花括号包裹
  },
  doSomthing:function(type) {
    //code
  }
}
//诸如sort()、map()、reduce()这些可以接收回调的数组方法，都可以使用箭函数语法减少编码量
//---------------------------------------------------------------
/**
 *  箭头函数没有自己的arguments对象
 *  却 始终可以访问外围函数的arguments对象
 */
function fn(num1,num2) {
  return () => arguments
}
console.log(fn(1,2,3,5,6)())
//---------------------------------------------------------------
/**
 *  依然能使用apply call bind
 *  卧槽，看来我真的不懂apply call bind
 */
let sum = (num1,num2) => num1 + num2;

console.log(sum.call(null,1,2))
console.log(sum.apply(null,[1,2]))
var boundSum = sum.bind(null,1,2)
console.log(boundSum())
//---------------------------------------------------------------
/**
 *  尾调用
 *  递归
 */




